﻿using System;
using System.IO;
using System.Text;
using System.Data;
using System.Data.SqlTypes;
using System.Data.SqlClient;
using System.Reflection;
using System.Collections;
using System.Globalization;
using System.Security.Cryptography;
using System.Runtime;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters;
using System.Runtime.Serialization.Formatters.Binary;
using Microsoft.SqlServer.Server;

namespace PickGold.SqlServer
{
	/// <summary>
	/// 位操作支持
	/// </summary>
	[Serializable]
	[SqlUserDefinedAggregate(Format.UserDefined, IsInvariantToDuplicates = true, IsInvariantToNulls = true, IsInvariantToOrder = true, IsNullIfEmpty = true, MaxByteSize = SqlUserDefinedAggregateAttribute.MaxByteSizeValue)]
	public sealed class AllBitAnd : IAggregate<SqlBinary, AllBitAnd>, INullable, IBinarySerialize
	{
		/// <summary/>
		private AllBit Value;

		/// <summary>
		/// 指示结构是否为 null。此属性为只读。
		/// </summary>
		public bool IsNull
		{
			get
			{
				if (this.Value.IsNull)
					return true;

				return false;
			}
		}

		/// <summary>
		/// 查询处理器使用此方法初始化聚合的计算
		/// 对于查询处理器正在聚合的每个组调用此方法一次
		/// 查询处理器可以选择重用聚合类的同一实例来计算多个组的聚合
		/// 方法应在上一次使用此实例后根据需要执行清除，并允许重新启动新的聚合计算
		/// </summary>
		public void Init()
		{
			this.Value = SqlBinary.Null;
		}

		/// <summary>
		/// 查询处理器使用此方法累计聚合值
		/// 对于正在聚合的组中的每个值调用此方法一次
		/// 查询处理器仅在为聚合类的指定实例调用Init方法之后才调用此方法
		/// 此方法的实现应更新实例的状态以反映正在传递的参数值的累计
		/// </summary>
		/// <param name="value"></param>
		public void Accumulate(SqlBinary value)
		{
			this.Value = AllBit.And(this.Value.IsNull ? null : this.Value, value.IsNull ? null : value.Value);
		}

		/// <summary>
		/// 可以将此聚合的另一实例与当前实例合并
		/// 查询处理器使用此方法合并聚合的多个部分计算
		/// </summary>
		/// <param name="value"></param>
		public void Merge(AllBitAnd value)
		{
			this.Value = AllBit.And(this.Value.IsNull ? null : this.Value, value.IsNull ? null : value.Value);
		}

		/// <summary/>
		public SqlBinary Terminate()
		{
			return this.Value;
		}

		void IBinarySerialize.Read(BinaryReader r)
		{
			this.Value.Read(r);
		}

		void IBinarySerialize.Write(BinaryWriter w)
		{
			this.Value.Write(w);
		}
	}

	/// <summary>
	/// 位操作支持
	/// </summary>
	[Serializable]
	[SqlUserDefinedAggregate(Format.UserDefined, IsInvariantToDuplicates = true, IsInvariantToNulls = false, IsInvariantToOrder = true, IsNullIfEmpty = true, MaxByteSize = SqlUserDefinedAggregateAttribute.MaxByteSizeValue)]
	public sealed class AllBitOr : IAggregate<SqlBinary, AllBitOr>, INullable, IBinarySerialize
	{
		private AllBit Value;

		/// <summary/>
		public bool IsNull
		{
			get
			{
				if (this.Value.IsNull)
					return true;

				return false;
			}
		}

		/// <summary/>
		public void Init()
		{
			this.Value = SqlBinary.Null;
		}

		/// <summary>
		/// 查询处理器使用此方法累计聚合值
		/// 对于正在聚合的组中的每个值调用此方法一次
		/// 查询处理器仅在为聚合类的指定实例调用Init方法之后才调用此方法
		/// 此方法的实现应更新实例的状态以反映正在传递的参数值的累计
		/// </summary>
		/// <param name="value"></param>
		public void Accumulate(SqlBinary value)
		{
			this.Value = AllBit.Or(this.Value.IsNull ? null : this.Value, value.IsNull ? null : value.Value);
		}

		/// <summary>
		/// 可以将此聚合的另一实例与当前实例合并
		/// 查询处理器使用此方法合并聚合的多个部分计算
		/// </summary>
		/// <param name="value"></param>
		public void Merge(AllBitOr value)
		{
			this.Value = AllBit.Or(this.Value.IsNull ? null : this.Value, value.IsNull ? null : value.Value);
		}

		/// <summary/>
		public SqlBinary Terminate()
		{
			return this.Value;
		}

		void IBinarySerialize.Read(BinaryReader r)
		{
			this.Value.Read(r);
		}

		void IBinarySerialize.Write(BinaryWriter w)
		{
			this.Value.Write(w);
		}
	}

	/// <summary/>
	struct AllBit : INullable, IBinarySerialize
	{
		public static readonly AllBit Null = new AllBit();

		public byte[] Value;

		public bool IsNull
		{
			get
			{
				if (this.Value == null)
					return true;

				return false;
			}
		}

		public void Init()
		{
			this.Value = null;
		}

		public SqlBinary Terminate()
		{
			if (this.Value == null)
				return SqlBinary.Null;

			var value = this.Value;
			this.Value = null;
			return new SqlBinary(value);
		}

		public void Read(BinaryReader r)
		{
			var ms = new MemoryStream();
			this.Value = new byte[short.MaxValue / 2];
			for (; ; )
			{
				var i = r.Read(this.Value, 0, this.Value.Length);
				if (i == 0)
					break;

				ms.Write(this.Value, 0, i);
			}
			this.Value = ms.ToArray();
		}

		public void Write(BinaryWriter w)
		{
			if (this.Value != null && this.Value.Length > 0)
				w.Write(this.Value, 0, this.Value.Length);
		}

		public static byte[] And(byte[] l, byte[] r)
		{
			if (l == null || r == null)
				return null;

			var ll = l.Length;
			var rl = r.Length;
			var vl = ll > rl ? rl : ll;
			var v = ll > rl ? l : r;
			for (var i = 0; i < vl; i++)
				v[i] = (byte)(l[i] & r[i]);
			for (var i = v.Length - 1; i >= vl; i--)
				v[i] = byte.MinValue;
			return v;
		}

		public static byte[] Or(byte[] l, byte[] r)
		{
			if (l == null)
				return r;

			if (r == null)
				return l;

			var ll = l.Length;
			if (ll == 0)
				return r;

			var rl = r.Length;
			if (rl == 0)
				return l;

			var v = ll > rl ? l : r;
			for (var i = 0; i < ll && i < rl; i++)
				v[i] = (byte)(l[i] | r[i]);
			return v;
		}

		public static implicit operator SqlBinary(AllBit value)
		{
			if (value.Value == null)
				return SqlBinary.Null;

			return value.Value;
		}

		public static implicit operator AllBit(SqlBinary value)
		{
			return new AllBit { Value = value.IsNull ? null : value.Value };
		}

		public static implicit operator byte[](AllBit value)
		{
			return value.Value;
		}

		public static implicit operator AllBit(byte[] value)
		{
			return new AllBit { Value = value };
		}
	}
}
